#include "morphological_operator.h"

MorphologicalOperator::MorphologicalOperator(PNM* img) :
    Transformation(img)
{
}

MorphologicalOperator::MorphologicalOperator(PNM* img, ImageViewer* iv) :
    Transformation(img, iv)
{
}

// abstract
const int MorphologicalOperator::morph(math::matrix<double>, math::matrix<bool>)
{
	return 0;
}

math::matrix<bool> MorphologicalOperator::getSE(int size, SE shape)
{
    switch (shape)
    {
    case Square:    return seSquare(size);
    case Cross:     return seCross(size);
    case XCross:    return seXCross(size);
    case VLine:     return seVLine(size);
    case HLine:     return seHLine(size);
    default:        return seSquare(size);
    }
}

math::matrix<bool> MorphologicalOperator::seSquare(int size)
{
    math::matrix<bool> ret(size, size);

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++)
		{
			ret(i,j) = true;
		}
	}

    return ret;
}

math::matrix<bool> MorphologicalOperator::seCross(int size)
{
    math::matrix<bool> ret(size, size);

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++)
		{
			if(i == size / 2 || j == size / 2) ret(i, j) = true;
			else ret(i,j) = false;
		}
	}

    return ret;
}

math::matrix<bool> MorphologicalOperator::seXCross(int size)
{
    math::matrix<bool> ret(size, size);

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++)
		{
			if(i == j) ret(i,j) = true;
			else if(size - j - 1 == i) ret(i,j) = true;
			else ret(i,j) = false;
		}
	}

    return ret;
}

math::matrix<bool> MorphologicalOperator::seVLine(int size)
{
    math::matrix<bool> ret(size, size);

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++)
		{
			if(j == size / 2) ret(i,j) = true;
			else ret(i,j) = false;
		}
	}

    return ret;
}

math::matrix<bool> MorphologicalOperator::seHLine(int size)
{
    math::matrix<bool> ret(size, size);

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++)
		{
			if(i == size / 2) ret(i,j) = true;
			else ret(i,j) = false;
		}
	}
    return ret;
}

PNM* MorphologicalOperator::transform()
{  
    int size  = getParameter("size").toInt();
    SE  shape = (MorphologicalOperator::SE) getParameter("shape").toInt();

    PNM* newImage = new PNM(image->width(), image->height(), QImage::Format_RGB32);

	auto mask = getSE(size, shape);

	int width = image->width();
	int height = image->height();

	if (image->format() == QImage::Format_Indexed8)
    {
        // Iterate over image space
        for (int x=0; x<width; x++)
            for (int y=0; y<height; y++)
            {
				auto window = getWindow(x, y, size, Channel::LChannel, Mode::RepeatEdge);

				int v = morph(window, mask);

                newImage->setPixel(x,y, v);
            }
    }
    else //if (image->format() == QImage::Format_RGB32)
    {
        // Iterate over image space
        for (int x=0; x<width; x++)
            for (int y=0; y<height; y++)
            {
				auto window = getWindow(x, y, size, Channel::RChannel, Mode::RepeatEdge);
				int r = morph(window, mask);    // Get the 0-255 value of the R channel

				window = getWindow(x, y, size, Channel::GChannel, Mode::RepeatEdge);
                int g = morph(window, mask);  // Get the 0-255 value of the G channel
                
				window = getWindow(x, y, size, Channel::BChannel, Mode::RepeatEdge);
				int b = morph(window, mask);   // Get the 0-255 value of the B channel

				QColor newPixel = QColor(r,g,b);
                newImage->setPixel(x,y, newPixel.rgb());
            }
    }

    return newImage;
}
